package net.sea.commons.util.zip;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
/**
 * 
 * 文件包含过滤器
 *
 * @author wangwei 
 */

public class FileIncludeFilter implements FileFilter {
	protected String baseDir=null; 
	
	protected String dirPattern=null;   
	
	protected String filenamePattern=null;

	/**
	 * 构造函数
	 * 
	 * @param baseDir	搜索文件的起始目錄
	 * @param dirPattern  目录匹配串，语法如下：<br>
	 * 		/	在根目录<br>
	 * 		?	匹配任何第一级目录(不包含子目录，如二级、三级目录等）<br>
	 * 		* 	匹配任何目录及其子目录<br>
	 * 		lib	第一级目录，且名称为lib<br>
	 * 		&#42;/lib		在目录名为lib的目录中<br>  
	 * 		lib/&#42;		lib目录的子目录中<br>
	 * 		dir1/dir2/&#42;	匹配dir1/dir2目录或其所有子目录<br> 
	 * 		dir1/dir2/dir3	匹配dir1/dir2/dir3目录<br> 
	 * 		&#42;/dir1/dir2	匹配路径中含有dir1/dir2的目录<p>
	 *  
	 * @param filenamePattern 文件名称匹配串（不带路径），语法如下：<br>
	 * 		filename1.jar	匹配文件名称为filename1.jar<br>
	 * 		*.ext			匹配	所有扩展名为ext的文件<br>
	 * 		filename1.*		匹配所有文件名为filename1，扩展名为任意的文件<br>
	 * 		*.*				匹配所有文件<br>
	 * 		*				匹配所有文件<br>
	 * 		abc*.jar		匹配所有以abc开头的jar文件<br>
	 * 		*abc.jar		匹配所有以abc结尾的jar文件<br>
	 * 		*abc*.jar		匹配所有包含abc的jar文件<br>
	 * 		ab*cd.jar		匹配所有以ab开头，cd结尾的文件<br>
	 */
	public FileIncludeFilter(File baseDir,String dirPattern,String filenamePattern) {
		if(baseDir==null)
			throw new IllegalArgumentException("baseDir parameter should not be null");
		if(!baseDir.exists())
			throw new RuntimeException("Directory "+baseDir.getAbsolutePath()+" not found.");
		try {
			this.baseDir=replace(baseDir.getCanonicalPath(),"\\","/");
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		setDirPattern(dirPattern);
		setFilenamePattern(filenamePattern);
	}
	
	public boolean accept(File pathname) {
		String dirpath=null;
		String filename=null;
		
		if(pathname.isDirectory()) {
			try {
				dirpath=pathname.getCanonicalPath();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else {
			try {
				dirpath=pathname.getParentFile().getCanonicalPath();
			} catch (IOException e) {
				e.printStackTrace();
			}
			filename=pathname.getName();
		}
		dirpath=replace(dirpath, "\\", "/");
		
		return matchDir(dirPattern, dirpath) && matchFilename(filenamePattern, filename);
	}

	/**
	 * 设置目录的匹配串
	 * 
	 * @param dirPattern  目录匹配串，语法如下：<br>
	 * 		/	在根目录<br>
	 * 		?	匹配任何第一级目录(不包含子目录，如二级、三级目录等）<br>
	 * 		* 	匹配任何目录及其子目录<br>
	 * 		lib	第一级目录，且名称为lib<br>
	 * 		&#42;/lib		在目录名为lib的目录中<br>  
	 * 		lib/&#42;		lib目录的子目录中<br>
	 * 		dir1/dir2/&#42;	匹配dir1/dir2目录或其所有子目录<br> 
	 * 		dir1/dir2/dir3	匹配dir1/dir2/dir3目录<br> 
	 * 		&#42;/dir1/dir2	匹配路径中含有dir1/dir2的目录<br> 
	 */
	private void setDirPattern(String dirPattern) {
		if(dirPattern!=null) {
			this.dirPattern=dirPattern.trim();
			
			int pos=dirPattern.indexOf("*");
			if(pos!=-1 && pos!=dirPattern.lastIndexOf("*") && 
					dirPattern.indexOf("/")!=-1)
				throw new IllegalArgumentException("Bad dir pattern format "+dirPattern);  //排除 */*
			
			if(dirPattern.indexOf("*")!=-1 && dirPattern.indexOf("/")!=-1 && dirPattern.length()==2)
				throw new IllegalArgumentException("Bad dir pattern format "+dirPattern);  //排除 “*/”，“/*”
		}
	}

	/**
	 * 设置文件名称（不带路径）的匹配串
	 * 
	 * @param filenamePattern 文件名称匹配串（不带路径），语法如下：<br>
	 * 		filename1.jar	匹配文件名称为filename1.jar<br>
	 * 		*.ext			匹配	所有扩展名为ext的文件<br>
	 * 		filename1.*		匹配所有文件名为filename1，扩展名为任意的文件<br>
	 * 		*.*				匹配所有文件<br>
	 * 		*				匹配所有文件<br>
	 * 		abc*.jar		匹配所有以abc开头的jar文件<br>
	 * 		*abc.jar		匹配所有以abc结尾的jar文件<br>
	 * 		*abc*.jar		匹配所有包含abc的jar文件<br>
	 * 		ab*cd.jar		匹配所有以ab开头，cd结尾的文件<br>
	 */
	private void setFilenamePattern(String filenamePattern) {
		if(filenamePattern!=null) {
			this.filenamePattern=filenamePattern.trim();
			if(filenamePattern.indexOf("**")!=-1)
				throw new IllegalArgumentException("Bad filename pattern "+filenamePattern);
		}
	}

	/**
	 * 判断目录路径是否匹配
	 * 
	 * @param pattern  目录匹配模板
	 * @param dirname	目录路径
	 * @return
	 */
	private boolean matchDir(String pattern,String dirName) {
		if(pattern==null || pattern.equals("*"))
			return true;
		
		if(pattern.equals("/")) {
			if(baseDir.equals(dirName))
				return true;
			else
				return false;
		}
		if(!dirName.startsWith(baseDir))
			return false;
		
		if(baseDir.equals(dirName))
			return false;
		
		String restDirName=dirName.substring(baseDir.length()+1);
		
		if(pattern.equals("?")) {
			if(restDirName.indexOf("/")==-1)
				return true;
			else
				return false;
		}
		
		int posPattern=pattern.indexOf("/");
		if(posPattern==-1 && pattern.equals(restDirName))
			return true;
		
		if(pattern.startsWith("*/")) {
			String pathToMatch=pattern.substring(2);
			if(restDirName==null)
				return true;
			
			return restDirName.endsWith("/"+pathToMatch) 
				|| restDirName.endsWith(pathToMatch);
		}
		
		if(pattern.endsWith("/*")) {
			String pathToMatch=pattern.substring(0,pattern.lastIndexOf("/*"));
			if(restDirName==null)
				return false;
			
			return restDirName.startsWith(pathToMatch) 
				|| restDirName.startsWith(pathToMatch+"/");
		}
		
		return pattern.equals(restDirName);
		
	}
	
	/**
	 * 判断文件名是否匹配
	 * 
	 * @param pattern 文件名匹配模板
	 * @param filename	文件名
	 * @return
	 */
	private boolean matchFilename(String pattern,String filename) {
		if(pattern==null || pattern.equals("*.*") || pattern.equals("*"))
			return true;
		
		if(filename==null)
			return false;
		
		String prefix=null;
		String ext=null;
		int pos=filename.lastIndexOf(".");
		if(pos!=-1) {
			prefix=filename.substring(0,pos);
			ext=filename.substring(pos+1);
		}else
			prefix=filename;
		
		String patternPrefix=null;
		String patternExt=null;
		int posPattern=pattern.lastIndexOf(".");
		if(posPattern!=-1) {
			patternPrefix=pattern.substring(0,posPattern);
			patternExt=pattern.substring(posPattern+1);
		}else
			patternPrefix=pattern;
		
		boolean prefixMatched=false;
		boolean extMatched=false;
		
		if(patternPrefix.equals("*"))
			prefixMatched=true;
		else if(patternPrefix.startsWith("*") && patternPrefix.endsWith("*")) {   //匹配*abc*
			String realPart=patternPrefix.substring(1,patternPrefix.length()-1);
			prefixMatched=prefix.indexOf(realPart)!=-1;
			
		}else if(patternPrefix.startsWith("*")) {  //匹配*abc
			String realPart=patternPrefix.substring(1);
			prefixMatched=prefix.endsWith(realPart);
			
		}else if(patternPrefix.endsWith("*")) {		//匹配abc*
			String realPart=patternPrefix.substring(0,patternPrefix.length()-1);
			prefixMatched=prefix.startsWith(realPart);
		
		}else if(patternPrefix.indexOf("*")>0) {	//匹配ab*cd
			int idx=patternPrefix.indexOf("*");
			String part1=patternPrefix.substring(0,idx);
			String part2=patternPrefix.substring(idx+1,patternPrefix.length());
			prefixMatched=prefix.startsWith(part1) && prefix.endsWith(part2);
			
		}else if(patternPrefix.equals(prefix)) {
			prefixMatched=true;
		}
		
		if(patternExt==null || patternExt.equals("*"))
			extMatched=true;
		else if(patternExt.equals(ext))
			extMatched=true;
		
		return prefixMatched && extMatched;
		
	}
	
	public String toString() {
		return "FileIncludeFilter:"+this.dirPattern+","+this.filenamePattern;
	}
	
	private static String replace(String inString, String oldPattern,
			String newPattern) {
		if (inString == null) {
			return null;
		}
		if (oldPattern == null || newPattern == null) {
			return inString;
		}

		StringBuffer sbuf = new StringBuffer();
		// output StringBuffer we'll build up
		int pos = 0; // our position in the old string
		int index = inString.indexOf(oldPattern);
		// the index of an occurrence we've found, or -1
		int patLen = oldPattern.length();
		while (index >= 0) {
			sbuf.append(inString.substring(pos, index));
			sbuf.append(newPattern);
			pos = index + patLen;
			index = inString.indexOf(oldPattern, pos);
		}
		sbuf.append(inString.substring(pos));

		// remember to append any characters to the right of a match
		return sbuf.toString();
	}

}